package model;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.multi.qrcode.QRCodeMultiReader;
import com.vandorenmes.argus.R;

import controller.App;


/**
 * Camera preview callback
 */
public class PreviewCallback implements Camera.PreviewCallback {
    private static final String TAG = PreviewCallback.class.getSimpleName();
    /**
     * Zxing multi format reader
     */
    //private final MultiFormatReader multiFormatReader = new MultiFormatReader();
    private final QRCodeMultiReader multiFormatReader = new QRCodeMultiReader();
    private Context context;
    /**
     * Handler to send messages
     *
     * @see CaptureHandler
     */
    private Handler handler;
    

    public PreviewCallback(Handler handler, Context context) {
        this.handler = handler;
        this.context = context;
    }
    
    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) 
    {
        Camera.Size previewSize = camera.getParameters().getPreviewSize();
        new DecodeAsyncTask(previewSize.width, previewSize.height).execute(bytes);        	
    }

    /**
     * Asynchronous task for decoding and finding barcode
     */
    //private class DecodeAsyncTask extends AsyncTask<byte[], Void, Result> {
	private class DecodeAsyncTask extends AsyncTask<byte[], Void, Result[]> {
		
		private Timer timer;
		private final int TIMER_DELAY = 8000;
        /**
         * Width of image
         */
        private int width;
        /**
         * Height of image
         */
        private int height;

        /**
         * @param width  Width of image
         * @param height Height of image
         */
        private DecodeAsyncTask(int width, int height) {
            this.width = width;
            this.height = height;
            timer = new Timer();
        }

        @Override
        protected void onPostExecute(Result[] results) 
        {
        	boolean atLeastOneResultExists = results != null && results[0] != null;
        	
        	if(atLeastOneResultExists)
        	{
        		handleDecodedQRcodes(results);
        	}
        	else
        	{
        		Log.i(TAG, "Decode fail.");
                if (handler != null) {
                    Message message = Message.obtain(handler, R.id.decode_failed);
                    message.sendToTarget();
                }
        	}
        }
        
        private void handleDecodedQRcodes(Result[] results)
        {
        	Log.i(TAG, "Decode success.");
            if (handler != null) 
            {
            	App app = ((App) ((Activity) context).getApplication());
                                
                String resultString = createDecodedQRresultString(results);
                
                boolean currentQrEqualsResultString = app.getCurrentQR().equals(resultString);
                
                if(!currentQrEqualsResultString)
                {
                	app.setCurrentQR(resultString);
                	Log.d("QR", "unique scanned code: " + resultString);
                	new WCFconnection(handler, context).execute(resultString);
                	timer.schedule(new emptyLabelTask(), TIMER_DELAY, 1000);
                }
            }           
        }
        
        private String createDecodedQRresultString(Result[] results)
        {
        	String resultString = "";
            for (Result result : results) 
            {
				Log.v("QR", result.toString());
				resultString += result.toString() + "_";
			}
            
            resultString = resultString.trim();
            resultString = resultString.substring(0, resultString.length() -1); //remove last underscore
            
            return resultString;
        }

        @Override
        protected Result[] doInBackground(byte[]... datas) 
        {
        	CameraManager cameraManager = CameraManager.getInstance();
            if (!cameraManager.hasCamera()) {
                return null;
            }
            
        	return checkBinaryBitmapForQRcodes(cameraManager, datas);
        }
        
	    private Result[] checkBinaryBitmapForQRcodes(CameraManager cameraManager, byte[]... datas)
	    {
            Result[] results = null;
            final PlanarYUVLuminanceSource source = cameraManager.buildLuminanceSource(datas[0], width, height, cameraManager.getBoundingRect());
            
            if (source != null) 
            {
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
                try 
                {
                	results = multiFormatReader.decodeMultiple(bitmap);
                	if(results.length == 0)
                		return null;
                		
                } catch (ReaderException re) {
                    // continue without finishing reading
                } finally {
                    multiFormatReader.reset();
                }
            }
            
            return results;
	    }
    }
	
	protected class emptyLabelTask extends TimerTask {

		@Override
		public void run() {
			Log.d("wcf", "end of delay, emptying label now...");
			
			Bundle bundle = new Bundle();
            bundle.putString(CaptureHandler.DECODED_DATA, "");
            
            Message message = Message.obtain(handler, R.id.decoded);
            message.setData(bundle);
            message.sendToTarget();
            
            ((App) ((Activity) context).getApplication()).setCurrentQR("");
            
		}
		
	}
}
